import pandas as pd
import numpy as np
from typing import Dict, List, Tuple, Optional
from pathlib import Path
import re
from .config import EXAM_WEIGHTS, EXAM_DISPLAY_NAMES

class EnhancedScoreAnalyzer:
    """增强版成绩分析器，提供更详细的学生成绩分析"""
    
    def __init__(self):
        """初始化分析器"""
        self.students = {}  # 存储所有学生的成绩数据
        self.exams = []  # 存储所有考试信息
        self.subjects = []  # 存储所有科目
        self.class_stats = {}  # 存储班级统计数据
        
    def load_exam_file(self, file_path: Path) -> Dict:
        """
        加载考试文件并解析
        
        Args:
            file_path: Excel文件路径
            
        Returns:
            考试信息字典
        """
        # 解析文件名获取考试信息
        exam_info = self._parse_filename(file_path)
        
        # 读取Excel文件
        df = pd.read_excel(file_path, header=1)  # 跳过第一行
        
        # 标准化列名
        df.columns = [
            "准考证号", "班级", "姓名", 
            "总分", "校次", "班次",
            "语文", "语文校次", "语文班次",
            "数学", "数学校次", "数学班次",
            "英语", "英语校次", "英语班次",
            "物理", "物理校次", "物理班次",
            "化学", "化学校次", "化学班次",
            "生物", "生物校次", "生物班次",
            "政治", "政治校次", "政治班次",
            "历史", "历史校次", "历史班次",
            "地理", "地理校次", "地理班次"
        ][:len(df.columns)]
        
        # 确保数值列为数值类型
        numeric_columns = [col for col in df.columns if not any(x in col for x in ["准考证号", "班级", "姓名"])]
        for col in numeric_columns:
            df[col] = pd.to_numeric(df[col], errors='coerce')
        
        # 确保准考证号为字符串
        df['准考证号'] = df['准考证号'].astype(str)
        
        # 添加考试信息
        exam_id = len(self.exams)
        exam_info['id'] = exam_id
        self.exams.append(exam_info)
        
        # 更新科目列表
        self._update_subjects(df)
        
        # 更新学生成绩数据
        self._update_student_scores(df, exam_info)
        
        # 计算班级统计数据
        self._calculate_class_stats(df, exam_info)
        
        return exam_info
    
    def _parse_filename(self, file_path: Path) -> Dict:
        """
        解析文件名获取考试信息
        
        Args:
            file_path: 文件路径
            
        Returns:
            考试信息字典
        """
        # 文件名解析正则表达式
        pattern = r"(\d{4})届(高一)([上下])学期(\d+月|期中|期末).*?(\d+)班"
        
        match = re.match(pattern, file_path.stem)
        if not match:
            raise ValueError(f"无效的文件名格式: {file_path.name}")
        
        semester = match.group(3)  # 上 or 下
        exam_type = match.group(4)  # 9月, 期中, 期末等
        
        # 组合学期和考试类型，用于唯一标识一个考试
        combined_key = f"{semester}_{exam_type}"
        
        # 查找权重和显示名称
        weight = EXAM_WEIGHTS.get(combined_key, 0)
        display_name = EXAM_DISPLAY_NAMES.get(combined_key, f"{semester}学期{exam_type}")
        
        return {
            "grade_year": match.group(1),
            "grade": match.group(2),
            "semester": semester,
            "exam_type": exam_type,
            "combined_key": combined_key,
            "display_name": display_name,
            "class_num": match.group(5),
            "weight": weight,
            "file_path": str(file_path)
        }
    
    def _update_subjects(self, df: pd.DataFrame):
        """
        更新科目列表
        
        Args:
            df: 考试数据DataFrame
        """
        # 获取所有科目列（不包含"校次"和"班次"的列）
        subject_cols = [col for col in df.columns if col not in ["准考证号", "班级", "姓名", "总分", "校次", "班次"] 
                        and "校次" not in col and "班次" not in col]
        
        # 更新科目列表
        for subject in subject_cols:
            if subject not in self.subjects:
                self.subjects.append(subject)
    
    def _update_student_scores(self, df: pd.DataFrame, exam_info: Dict):
        """
        更新学生成绩数据
        
        Args:
            df: 考试数据DataFrame
            exam_info: 考试信息
        """
        for _, row in df.iterrows():
            student_id = row['准考证号']
            
            # 如果学生不存在，则创建新的学生记录
            if student_id not in self.students:
                self.students[student_id] = {
                    'id': student_id,
                    'name': row['姓名'],
                    'class': row['班级'],
                    'exams': {}
                }
            
            # 添加考试成绩
            exam_id = exam_info['id']
            self.students[student_id]['exams'][exam_id] = {
                'exam_info': exam_info,
                'scores': {}
            }
            
            # 添加总分和排名
            self.students[student_id]['exams'][exam_id]['scores']['总分'] = row['总分']
            self.students[student_id]['exams'][exam_id]['scores']['校次'] = row['校次']
            self.students[student_id]['exams'][exam_id]['scores']['班次'] = row['班次']
            
            # 添加各科目成绩和排名
            for subject in self.subjects:
                if subject in df.columns:
                    self.students[student_id]['exams'][exam_id]['scores'][subject] = row[subject]
                    
                    # 添加科目排名（如果存在）
                    subject_school_rank = f"{subject}校次"
                    subject_class_rank = f"{subject}班次"
                    
                    if subject_school_rank in df.columns:
                        self.students[student_id]['exams'][exam_id]['scores'][subject_school_rank] = row[subject_school_rank]
                    
                    if subject_class_rank in df.columns:
                        self.students[student_id]['exams'][exam_id]['scores'][subject_class_rank] = row[subject_class_rank]
    
    def _calculate_class_stats(self, df: pd.DataFrame, exam_info: Dict):
        """
        计算班级统计数据
        
        Args:
            df: 考试数据DataFrame
            exam_info: 考试信息
        """
        exam_id = exam_info['id']
        
        # 如果班级统计数据不存在，则创建
        if exam_id not in self.class_stats:
            self.class_stats[exam_id] = {
                'exam_info': exam_info,
                'stats': {}
            }
        
        # 计算总分统计
        self.class_stats[exam_id]['stats']['总分'] = {
            'mean': df['总分'].mean(),
            'median': df['总分'].median(),
            'std': df['总分'].std(),
            'max': df['总分'].max(),
            'min': df['总分'].min()
        }
        
        # 计算各科目统计
        for subject in self.subjects:
            if subject in df.columns:
                self.class_stats[exam_id]['stats'][subject] = {
                    'mean': df[subject].mean(),
                    'median': df[subject].median(),
                    'std': df[subject].std(),
                    'max': df[subject].max(),
                    'min': df[subject].min()
                }
    
    def analyze_student(self, student_id: str) -> Dict:
        """
        分析单个学生的成绩
        
        Args:
            student_id: 学生准考证号
            
        Returns:
            学生成绩分析结果
        """
        if student_id not in self.students:
            raise ValueError(f"学生 {student_id} 不存在")
        
        student = self.students[student_id]
        
        # 使用考试权重排序（从晚到早）
        sorted_exams = sorted(student['exams'].items(), 
                             key=lambda x: x[1]['exam_info']['weight'],
                             reverse=True)  # 按权重从大到小排序（最近的考试权重最大）
        
        # 提取考试信息
        exam_data = {
            'exams': [exam[1]['exam_info'] for exam in sorted_exams],
        }
        
        # 基本信息
        result = {
            "基本信息": {
                "姓名": student['name'],
                "准考证号": student['id'],
                "班级": student['class']
            },
            "成绩趋势": self._analyze_trends(student, sorted_exams),
            "科目分析": self._analyze_subjects(student, sorted_exams),
            "排名分析": self._analyze_rankings(student, sorted_exams),
            "班级对比": self._analyze_class_comparison(student, sorted_exams),
            "优劣势分析": self._analyze_strengths_weaknesses(student, sorted_exams),
            "进步分析": self._analyze_improvement(student, sorted_exams),
            "缺考记录": self._analyze_absences(student, sorted_exams)
        }
        
        return result, exam_data
    
    def _analyze_trends(self, student: Dict, sorted_exams: List) -> Dict:
        """
        分析成绩趋势
        
        Args:
            student: 学生数据
            sorted_exams: 排序后的考试数据
            
        Returns:
            成绩趋势分析结果
        """
        # 总分走势
        total_scores = [exam[1]['scores'].get('总分') for exam in sorted_exams]
        
        # 总分校次走势
        total_school_ranks = [exam[1]['scores'].get('校次') for exam in sorted_exams]
        
        # 各科目走势
        subject_trends = {}
        subject_rank_trends = {}
        
        for subject in self.subjects:
            # 科目分数
            scores = [exam[1]['scores'].get(subject) for exam in sorted_exams]
            if any(score is not None for score in scores):
                subject_trends[subject] = scores
            
            # 科目校次
            school_rank_key = f"{subject}校次"
            school_ranks = [exam[1]['scores'].get(school_rank_key) for exam in sorted_exams]
            if any(rank is not None for rank in school_ranks):
                subject_rank_trends[subject] = school_ranks
        
        return {
            "总分走势": total_scores,
            "总分校次走势": total_school_ranks,
            "各科走势": subject_trends,
            "各科校次走势": subject_rank_trends
        }
    
    def _analyze_subjects(self, student: Dict, sorted_exams: List) -> Dict:
        """
        分析各科目表现
        
        Args:
            student: 学生数据
            sorted_exams: 排序后的考试数据
            
        Returns:
            科目分析结果
        """
        # 计算各科目平均分和标准差
        subject_stats = {}
        for subject in self.subjects:
            scores = [exam[1]['scores'].get(subject) for exam in sorted_exams]
            valid_scores = [score for score in scores if score is not None]
            
            if valid_scores:
                subject_stats[subject] = {
                    'mean': np.mean(valid_scores),
                    'std': np.std(valid_scores) if len(valid_scores) > 1 else 0,
                    'max': max(valid_scores),
                    'min': min(valid_scores),
                    'latest': valid_scores[-1] if valid_scores else None
                }
        
        # 找出优势和弱势科目
        if subject_stats:
            # 按平均分排序
            sorted_subjects = sorted(subject_stats.items(), key=lambda x: x[1]['mean'], reverse=True)
            
            # 最稳定和波动最大的科目
            stability_sorted = sorted(subject_stats.items(), key=lambda x: x[1]['std'])
            
            return {
                "优势科目": sorted_subjects[0][0],
                "弱势科目": sorted_subjects[-1][0],
                "最稳定科目": stability_sorted[0][0],
                "波动最大科目": stability_sorted[-1][0] if len(stability_sorted) > 1 else stability_sorted[0][0],
                "科目详情": subject_stats
            }
        
        return {
            "优势科目": None,
            "弱势科目": None,
            "最稳定科目": None,
            "波动最大科目": None,
            "科目详情": {}
        }
    
    def _analyze_rankings(self, student: Dict, sorted_exams: List) -> Dict:
        """
        分析排名变化
        
        Args:
            student: 学生数据
            sorted_exams: 排序后的考试数据
            
        Returns:
            排名分析结果
        """
        # 总分排名变化
        school_ranks = [exam[1]['scores'].get('校次') for exam in sorted_exams]
        class_ranks = [exam[1]['scores'].get('班次') for exam in sorted_exams]
        
        # 各科目排名变化
        subject_rankings = {}
        for subject in self.subjects:
            school_rank_key = f"{subject}校次"
            class_rank_key = f"{subject}班次"
            
            subject_school_ranks = [exam[1]['scores'].get(school_rank_key) for exam in sorted_exams]
            subject_class_ranks = [exam[1]['scores'].get(class_rank_key) for exam in sorted_exams]
            
            if any(rank is not None for rank in subject_school_ranks) or any(rank is not None for rank in subject_class_ranks):
                subject_rankings[subject] = {
                    "校次": subject_school_ranks,
                    "班次": subject_class_ranks
                }
        
        # 计算排名统计
        school_rank_stats = self._calculate_rank_stats(school_ranks)
        class_rank_stats = self._calculate_rank_stats(class_ranks)
        
        return {
            "校次": school_rank_stats,
            "班次": class_rank_stats,
            "科目排名": subject_rankings
        }
    
    def _calculate_rank_stats(self, ranks: List) -> Dict:
        """
        计算排名统计数据
        
        Args:
            ranks: 排名列表
            
        Returns:
            排名统计结果
        """
        valid_ranks = [rank for rank in ranks if rank is not None]
        
        if not valid_ranks:
            return {
                "数据": ranks,
                "最好": None,
                "最差": None,
                "平均": None,
                "变化趋势": None
            }
        
        # 计算变化趋势（正值表示排名下降，负值表示排名上升）
        changes = []
        for i in range(1, len(valid_ranks)):
            change = valid_ranks[i] - valid_ranks[i-1]
            changes.append(change)
        
        # 判断整体趋势
        if changes:
            avg_change = sum(changes) / len(changes)
            if avg_change > 0:
                trend = "下降"
            elif avg_change < 0:
                trend = "上升"
            else:
                trend = "稳定"
        else:
            trend = "未知"
        
        return {
            "数据": ranks,
            "最好": min(valid_ranks),
            "最差": max(valid_ranks),
            "平均": sum(valid_ranks) / len(valid_ranks),
            "变化趋势": trend
        }
    
    def _analyze_class_comparison(self, student: Dict, sorted_exams: List) -> Dict:
        """
        分析学生与班级平均水平的对比
        
        Args:
            student: 学生数据
            sorted_exams: 排序后的考试数据
            
        Returns:
            班级对比分析结果
        """
        comparison = {}
        
        # 总分对比
        total_score_diff = []
        for exam in sorted_exams:
            exam_id = exam[0]
            student_score = exam[1]['scores'].get('总分')
            
            if exam_id in self.class_stats and student_score is not None:
                class_mean = self.class_stats[exam_id]['stats']['总分']['mean']
                diff = student_score - class_mean
                total_score_diff.append(diff)
            else:
                total_score_diff.append(None)
        
        # 各科目对比
        subject_diff = {}
        for subject in self.subjects:
            diffs = []
            for exam in sorted_exams:
                exam_id = exam[0]
                student_score = exam[1]['scores'].get(subject)
                
                if exam_id in self.class_stats and subject in self.class_stats[exam_id]['stats'] and student_score is not None:
                    class_mean = self.class_stats[exam_id]['stats'][subject]['mean']
                    diff = student_score - class_mean
                    diffs.append(diff)
                else:
                    diffs.append(None)
            
            if any(diff is not None for diff in diffs):
                subject_diff[subject] = diffs
        
        comparison["总分差异"] = total_score_diff
        comparison["科目差异"] = subject_diff
        
        # 计算优势科目（相对于班级平均水平）
        avg_diffs = {}
        for subject, diffs in subject_diff.items():
            valid_diffs = [diff for diff in diffs if diff is not None]
            if valid_diffs:
                avg_diffs[subject] = sum(valid_diffs) / len(valid_diffs)
        
        if avg_diffs:
            sorted_diffs = sorted(avg_diffs.items(), key=lambda x: x[1], reverse=True)
            comparison["相对优势科目"] = sorted_diffs[0][0]
            comparison["相对弱势科目"] = sorted_diffs[-1][0]
        else:
            comparison["相对优势科目"] = None
            comparison["相对弱势科目"] = None
        
        return comparison
    
    def _analyze_strengths_weaknesses(self, student: Dict, sorted_exams: List) -> Dict:
        """
        分析学生的优势和弱势
        
        Args:
            student: 学生数据
            sorted_exams: 排序后的考试数据（从晚到早）
            
        Returns:
            优劣势分析结果
        """
        # 获取最近一次考试的成绩（由于考试是从晚到早排序的，所以最近的考试是第一个）
        latest_exam = sorted_exams[0] if sorted_exams else None
        
        if not latest_exam:
            return {
                "优势项目": [],
                "弱势项目": [],
                "建议": []
            }
        
        latest_scores = latest_exam[1]['scores']
        
        # 计算各科目得分率（假设满分为100）
        score_rates = {}
        for subject in self.subjects:
            if subject in latest_scores and latest_scores[subject] is not None:
                score_rates[subject] = latest_scores[subject] / 100
        
        # 按得分率排序
        sorted_rates = sorted(score_rates.items(), key=lambda x: x[1], reverse=True)
        
        # 确定优势和弱势科目（前1/3为优势，后1/3为弱势）
        n = len(sorted_rates)
        strengths = sorted_rates[:max(1, n // 3)]
        weaknesses = sorted_rates[min(n - 1, n * 2 // 3):]
        
        # 生成建议
        suggestions = []
        
        # 针对弱势科目的建议
        for subject, rate in weaknesses:
            if rate < 0.6:
                suggestions.append(f"加强{subject}基础知识学习，提高基本分")
            elif rate < 0.8:
                suggestions.append(f"针对{subject}的中等难度题目进行专项训练")
            else:
                suggestions.append(f"提高{subject}解决难题的能力，争取满分")
        
        # 针对排名的建议
        if '校次' in latest_scores and latest_scores['校次'] is not None:
            school_rank = latest_scores['校次']
            if school_rank > 100:
                suggestions.append("制定合理的学习计划，全面提高各科成绩")
            elif school_rank > 50:
                suggestions.append("保持优势科目，同时提高弱势科目，争取进入前50名")
            elif school_rank > 20:
                suggestions.append("针对性提高弱势科目，争取进入前20名")
            else:
                suggestions.append("保持良好学习状态，巩固优势，争取更好成绩")
        
        return {
            "优势项目": [{"科目": subject, "得分率": rate} for subject, rate in strengths],
            "弱势项目": [{"科目": subject, "得分率": rate} for subject, rate in weaknesses],
            "建议": suggestions
        }
    
    def _analyze_improvement(self, student: Dict, sorted_exams: List) -> Dict:
        """
        分析学生的进步情况
        
        Args:
            student: 学生数据
            sorted_exams: 排序后的考试数据（从晚到早）
            
        Returns:
            进步分析结果
        """
        if len(sorted_exams) < 2:
            return {
                "总分进步": None,
                "科目进步": {},
                "排名进步": None
            }
        
        # 注意：由于考试是从晚到早排序的，所以最早的考试是最后一个，最晚的考试是第一个
        earliest_exam = sorted_exams[-1]  # 最早的考试（如9月）
        latest_exam = sorted_exams[0]     # 最晚的考试（如期末）
        
        # 计算总分进步（最晚的考试减去最早的考试）
        earliest_total = earliest_exam[1]['scores'].get('总分')
        latest_total = latest_exam[1]['scores'].get('总分')
        
        total_improvement = None
        if earliest_total is not None and latest_total is not None:
            total_improvement = latest_total - earliest_total
        
        # 计算各科目进步
        subject_improvement = {}
        for subject in self.subjects:
            earliest_score = earliest_exam[1]['scores'].get(subject)
            latest_score = latest_exam[1]['scores'].get(subject)
            
            if earliest_score is not None and latest_score is not None:
                improvement = latest_score - earliest_score
                subject_improvement[subject] = improvement
        
        # 计算排名进步
        earliest_rank = earliest_exam[1]['scores'].get('校次')
        latest_rank = latest_exam[1]['scores'].get('校次')
        
        rank_improvement = None
        if earliest_rank is not None and latest_rank is not None:
            # 注意：排名是越小越好，所以用早期的排名减去最近的排名
            rank_improvement = earliest_rank - latest_rank
        
        # 找出进步最大和退步最大的科目
        if subject_improvement:
            sorted_improvement = sorted(subject_improvement.items(), key=lambda x: x[1], reverse=True)
            most_improved = sorted_improvement[0]
            least_improved = sorted_improvement[-1]
        else:
            most_improved = None
            least_improved = None
        
        return {
            "总分进步": total_improvement,
            "科目进步": subject_improvement,
            "排名进步": rank_improvement,
            "进步最大科目": most_improved[0] if most_improved else None,
            "进步最大分值": most_improved[1] if most_improved else None,
            "退步最大科目": least_improved[0] if least_improved and least_improved[1] < 0 else None,
            "退步最大分值": least_improved[1] if least_improved and least_improved[1] < 0 else None
        }
    
    def _analyze_absences(self, student: Dict, sorted_exams: List) -> Dict:
        """
        分析缺考情况
        
        Args:
            student: 学生数据
            sorted_exams: 排序后的考试数据
            
        Returns:
            缺考分析结果
        """
        absences = {}
        total_absences = 0
        
        # 检查总分缺考
        for i, exam in enumerate(sorted_exams):
            exam_type = exam[1]['exam_info']['exam_type']
            scores = exam[1]['scores']
            
            # 检查总分是否缺考
            if scores.get('总分') is None:
                if exam_type not in absences:
                    absences[exam_type] = []
                absences[exam_type].append("总分")
                total_absences += 1
            
            # 检查各科目是否缺考
            for subject in self.subjects:
                if subject in scores and scores[subject] is None:
                    if exam_type not in absences:
                        absences[exam_type] = []
                    if subject not in absences[exam_type]:
                        absences[exam_type].append(subject)
                        total_absences += 1
        
        return {
            "缺考总次数": total_absences,
            "缺考详情": absences
        }
    
    def get_all_students(self) -> List[Dict]:
        """
        获取所有学生的基本信息
        
        Returns:
            学生基本信息列表
        """
        return [
            {
                "id": student_id,
                "name": student_data["name"],
                "class": student_data["class"]
            }
            for student_id, student_data in self.students.items()
        ] 